package org.keyroy.map.core.manages;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;

import org.keyroy.map.core.animation.Animation;
import org.keyroy.map.core.sprite.Sprite;
import org.keyroy.util.Base64;
import org.keyroy.util.KList;
import org.keyroy.util.KMap;
import org.keyroy.util.tag.Tag;
import org.keyroy.util.tag.XmlObject;
import org.keyroy.util.tag.XmlSupport;

public class ResourceManage extends XmlObject {
	public static Hashtable<String, Animation> animationBuf = new Hashtable<String, Animation>();
	public static KList<Resource> resourcesBuf = new KList<Resource>();
	public static KMap<Sprite> spritesBuf = new KMap<Sprite>();

	public static void reset() {
		animationBuf.clear();
		resourcesBuf.clear();
		spritesBuf.clear();
	}

	public static void add(Resource resource) {
		if (resource.ID == 0) {
			int ID = 1;
			while (resourcesBuf.get(ID) != null) {
				ID++;
			}
			resource.ID = ID;
		}
		resourcesBuf.set(resource.ID, resource);
		addSprite(resource);
	}

	public static void remove(Resource resource) {
		resourcesBuf.remove(resource.ID);
		removeSprite(resource);
	}

	private static final void addSprite(Resource resource) {
		Sprite[] sprites = resource.makeSprites();
		if (sprites != null) {
			for (int i = 0; i < sprites.length; i++) {
				add(sprites[i]);
			}
		}
	}

	private static final void removeSprite(Resource resource) {
		Sprite[] sprites = resource.makeSprites();
		if (sprites != null) {
			for (int i = 0; i < sprites.length; i++) {
				remove(sprites[i]);
			}
		}
	}

	public static final void add(Sprite sprite) {
		spritesBuf.set(sprite.getResourceID(), sprite.getQueueID(), sprite);
	}

	public static final void remove(Sprite sprite) {
		sprite = spritesBuf.remove(sprite.getResourceID(), sprite.getQueueID());
		sprite.ID = Sprite.SPRITE_DELETE_ID;
	}

	public static Sprite getSprite(int resourceID, int queueID) {
		Resource resource = getResource(resourceID);
		if (resource != null) {
			return getSprite(resource, queueID);
		}

		return null;
	}

	public static Sprite getSprite(Resource resource, int queueID) {
		Sprite sprite = spritesBuf.get(resource.ID, queueID);
		if (sprite == null) {
			sprite = resource.makeSprites(queueID);
			spritesBuf.set(resource.ID, queueID, sprite);
		}

		return sprite;
	}

	public static Sprite getSprite(Resource resource, int x, int y) {
		Sprite sprite = spritesBuf.get(resource.ID, resource.getQueueID(x, y));
		if (sprite == null) {
			sprite = resource.makeSprites(x, y);
			spritesBuf.set(resource.ID, sprite.getQueueID(), sprite);
		}

		return sprite;
	}

	public static Sprite getSprite(int ID) {
		return getSprite(Sprite.getResourceID(ID), Sprite.getQueueID(ID));
	}

	public static Resource getResource(int ID) {
		return resourcesBuf.get(ID);
	}

	public static Resource getResource(Sprite sprite) {
		return getResource(sprite.getResourceID());
	}

	public static void add(Animation animation) {
		animationBuf.put(animation.name, animation);
	}
	
	public static Animation getAnimation(String name) {
		return animationBuf.get(name);
	}

	@Override
	public void initTag(Tag tag) {
		{ // resource
			tag.addChild(resourcesBuf);
		}

		{ // block
			List<Integer> list = new ArrayList<Integer>();
			List<Sprite> sprites = spritesBuf.getList();
			for (int i = 0; i < sprites.size(); i++) {
				Sprite sprite = sprites.get(i);
				if (sprite != null && sprite.isBlock) {
					list.add(sprite.ID);
				}
			}
			String blockString = intArray2String(list);
			if (blockString != null) {
				tag.addParameter("block", blockString);
			}
		}

		{ // animations
			tag.addChild(animationBuf.elements());
		}

	}

	@Override
	public void initObj(Tag tag) {
		reset();

		{ // ressource
			List<XmlSupport> xmlSupports = tag.getChildObjectArray(Resource.class);
			Collections.sort(xmlSupports, new Comparator<XmlSupport>() {

				@Override
				public int compare(XmlSupport o1, XmlSupport o2) {
					Resource r1 = (Resource) o1;
					Resource r2 = (Resource) o2;
					return r1.ID - r2.ID;
				}
			});

			for (int i = 0; i < xmlSupports.size(); i++) {
				Resource resource = (Resource) xmlSupports.get(i);
				add(resource);
			}
		}

		{ // block
			String blockString = tag.getParameterValue("block");
			if (blockString != null) {
				List<Integer> integers = string2IntArray(blockString);
				for (int i = 0; i < integers.size(); i++) {
					Sprite sprite = getSprite(integers.get(i));
					if (sprite != null) {
						sprite.isBlock = true;
					}
				}
			}
		}

		{ // animations
			List<XmlSupport> xmlSupports = tag.getChildObjectArray(Animation.class);
			for (int i = 0; i < xmlSupports.size(); i++) {
				Animation animation = (Animation) xmlSupports.get(i);
				add(animation);
			}
		}
	}

	private static final String intArray2String(List<Integer> integers) {
		ByteBuffer buffer = ByteBuffer.allocate(integers.size() * 4);
		for (int i = 0; i < integers.size(); i++) {
			buffer.putInt(integers.get(i));
		}
		if (integers.size() == 0) {
			return null;
		}
		byte[] data = buffer.array();
		return new String(Base64.encode(data));
	}

	private static final List<Integer> string2IntArray(String string) {
		List<Integer> list = new ArrayList<Integer>();
		byte[] data = Base64.decode(string.getBytes());
		ByteBuffer byteBuffer = ByteBuffer.wrap(data);
		int size = data.length / 4;
		for (int i = 0; i < size; i++) {
			list.add(byteBuffer.getInt());
		}

		return list;
	}

}
